<template>
    <div>
        <canvas
            class="my-canvas"
            :width="width"
            :height="height"
            @click="canvasClickEvent($event)"
            :style="{ width: width + 'px', height: height + 'px' }"
        ></canvas>
        <img class="my-img" src="/11.png" />
        <div
            class="clip"
            :style="{
                top: clipRect.top + 'px',
                left: clipRect.left + 'px',
                width: clipRect.width + 'px',
                height: clipRect.height + 'px'
            }"
        >
            <div class="dot lt"></div>
            <div
                class="dot t"
                :style="{
                    left: clipRect.width / 2 - 5 + 'px'
                }"
            ></div>
            <div class="dot rt"></div>
            <div
                class="dot l"
                :style="{
                    top: clipRect.height / 2 - 5 + 'px'
                }"
            ></div>
            <div
                class="dot r"
                :style="{
                    top: clipRect.height / 2 - 5 + 'px'
                }"
            ></div>
            <div class="dot lb"></div>
            <div
                class="dot b"
                :style="{
                    left: clipRect.width / 2 - 5 + 'px'
                }"
            ></div>
            <div class="dot rb"></div>
        </div>
        <el-button @click="clipFace">剪裁</el-button>
    </div>
</template>

<script>
export default {
    props: {
        width: {
            type: Number,
            default: 600
        },
        height: {
            type: Number,
            default: 500
        }
    },
    data() {
        return {
            clipRect: {
                top: 0,
                left: 0,
                width: 0,
                height: 0
            },
            canvasDom: null, // canvas 标签
            canvasCtx: null, // canvas 上下文
            imgDom: null,
            mouseClipDown: false, // 截图
            wheelDirection: '', // 滚动的方向
            mouseOption: {
                zoom: 0.1, //  默认每次的缩放比例
                maxScale: 5, // 最大放大比例
                minScale: 0.2, // 最小缩小比例
                scale: 1, // 当前比例
                mouseX: 0, // 点击后鼠标当前位置
                mouseY: 0, // 点击后鼠标当前位置
                movementX: 0, // 鼠标移动的位置
                movementY: 0, // 鼠标移动的位置
                danW: 0, // 单次图片改变的长度
                danH: 0 // 单次图片改变的长度
            },
            // 图片位置
            imgRect: {
                ix: 0,
                iy: 0,
                iwidth: 0,
                iheight: 0,
                dx: 0,
                dy: 0,
                dwidth: 0,
                dheight: 0
            },
            // 框位置
            strokeRect: [
                {
                    ix: 5,
                    iy: 5,
                    iwidth: 50,
                    iheight: 50,
                    dx: 5,
                    dy: 5,
                    dwidth: 50,
                    dheight: 50
                },
                {
                    ix: 100,
                    iy: 150,
                    iwidth: 60,
                    iheight: 30,
                    dx: 100,
                    dy: 150,
                    dwidth: 60,
                    dheight: 30
                }
            ]
        }
    },
    mounted() {
        this.initCanvas()
    },
    methods: {
        clipFace() {
            this.removeListener()
            this.addClipListener()
        },
        addClipListener() {
            this.canvasDom.addEventListener('mousedown', this.clipDown)
            this.canvasDom.addEventListener('mouseup', this.clipUp)
        },
        removeClipListener() {
            this.canvasDom.removeEventListener('mousedown', this.clipDown)
            this.canvasDom.removeEventListener('mouseup', this.clipUp)
        },
        clipDown(e) {
            console.log(e)
            this.mouseClipDown = true
            this.canvasDom.addEventListener('mousemove', this.clipMove)
            this.clipRect.top = e.pageY
            this.clipRect.left = e.pageX
        },
        clipMove(e) {
            console.log(12313)
            if (this.mouseClipDown) {
                this.clipRect.width += e.movementX
                this.clipRect.height += e.movementY
            }
        },
        clipUp(e) {
            console.log(123132221231)
            this.mouseClipDown = false
            this.removeClipListener()
            this.canvasDom.removeEventListener('mousemove', this.clipMove)
        },
        canvasClickEvent(e) {
            let { mouseX, mouseY } = this.getMouseRect(e)
            this.strokeRect.forEach((item) => {
                if (
                    mouseX >= item.dx &&
                    mouseX <= item.dx + item.dwidth &&
                    mouseY >= item.dy &&
                    mouseY <= item.dy + item.dheight
                ) {
                    this.canvasCtx.strokeStyle = '#ff0000'
                    this.canvasCtx.strokeRect(item.dx, item.dy, item.dwidth, item.dheight)
                    this.getClipImg(this.canvasCtx.getImageData(item.dx, item.dy, item.dwidth, item.dheight))
                } else {
                    this.canvasCtx.strokeStyle = '#00ff00'
                    this.canvasCtx.strokeRect(item.dx, item.dy, item.dwidth, item.dheight)
                }
            })
        },
        // 获取截选图片，通过 canvas 转换图片
        getClipImg(imgData) {
            let newCanvas = document.createElement('canvas')
            newCanvas.width = 150
            newCanvas.height = 150
            let newCtx = newCanvas.getContext('2d')
            newCtx.putImageData(imgData, 0, 0)
            console.log(newCanvas.toDataURL(), '截图后的BASE64格式的图片')
            this.$emit('changeClipImgData', newCanvas.toDataURL())
        },
        // 添加事件监听
        addListener() {
            this.canvasDom.addEventListener('mousewheel', this.canvasMouseWheel)
            this.canvasDom.addEventListener('mousedown', this.canvasMouseDown)
            this.canvasDom.addEventListener('mouseup', this.canvasMouseUp)
        },
        removeListener() {
            this.canvasDom.removeEventListener('mousewheel', this.canvasMouseWheel)
            this.canvasDom.removeEventListener('mousedown', this.canvasMouseDown)
            this.canvasDom.removeEventListener('mouseup', this.canvasMouseUp)
        },
        // 滚动
        canvasMouseWheel(e) {
            let { mouseX, mouseY } = this.getMouseRect(e)
            this.mouseOption.mouseX = mouseX
            this.mouseOption.mouseY = mouseY
            // 判断当前怎么滚
            let direction = e.wheelDelta < 0 ? 'down' : 'up'
            if (direction === 'down' && e.wheelDelta <= -120 && this.mouseOption.scale > this.mouseOption.minScale) {
                this.wheelDirection = 'down'
                this.mouseOption.scale -= this.mouseOption.zoom
                this.drawImage(e)
            }
            if (direction === 'up' && e.wheelDelta >= 120 && this.mouseOption.scale < this.mouseOption.maxScale) {
                this.wheelDirection = 'up'
                this.mouseOption.scale += this.mouseOption.zoom
                this.drawImage(e)
            }
            this.wheelDirection = ''
            e.preventDefault()
        },
        // 鼠标点击
        canvasMouseDown() {
            this.mouseOption.isMouseMove = true
            this.canvasDom.addEventListener('mousemove', this.canvasMouseMove)
        },
        // 鼠标移动
        canvasMouseMove(e) {
            if (this.mouseOption.isMouseMove) {
                console.log(e.movementX, e.movementY)
                this.mouseOption.movementX = e.movementX
                this.mouseOption.movementY = e.movementY
                this.drawImage()
            }
        },
        // 鼠标松开
        canvasMouseUp() {
            this.mouseOption.isMouseMove = false
            this.canvasDom.removeEventListener('mousemove', this.canvasMouseMove)
        },
        /**
         * 绘制图片
         */
        drawImage() {
            // 清空当前画布
            this.canvasCtx.clearRect(0, 0, this.width, this.height)
            // 重新绘制图片
            let { nx, ny, nwidth, nheight } = this.computedWheelRect(this.imgRect)
            this.canvasCtx.drawImage(this.imgDom, nx, ny, nwidth, nheight)
            // 重新绘制框
            this.drawStroke()
        },
        drawStroke() {
            this.strokeRect.forEach((item) => {
                // 重新绘制
                item.dx = this.imgRect.dx + (item.ix - this.imgRect.ix) * this.mouseOption.scale
                item.dy = this.imgRect.dy + (item.iy - this.imgRect.iy) * this.mouseOption.scale
                item.dwidth = item.iwidth * this.mouseOption.scale
                item.dheight = item.iheight * this.mouseOption.scale
                this.canvasCtx.strokeStyle = '#00ff00'
                this.canvasCtx.strokeRect(item.dx, item.dy, item.dwidth, item.dheight)
            })
        },
        /**
         * @desc 获取鼠标位置
         */
        getMouseRect(e) {
            let rect = this.canvasDom.getBoundingClientRect()
            return {
                mouseX: e.clientX - rect.left,
                mouseY: e.clientY - rect.top
            }
        },
        /**
         * @desc 处理所有内容放大缩小过程中的位置处理
         * @param { Number } oldX 距离左侧位置
         * @param { Number } oldY 距离上侧位置
         * @return { Object } { newX, newY } 改变后的位置大小
         */
        computedWheelRect(dom) {
            let { ix, iy, dx, dy, dwidth, dheight } = dom
            let nx = 0,
                ny = 0,
                nwidth = 0,
                nheight = 0
            // 向下滚动
            if (this.wheelDirection === 'down') {
                nx = dx + Math.abs(this.mouseOption.mouseX - dx) * (1 - (dwidth - this.mouseOption.danW) / dwidth)
                ny = dy + Math.abs(this.mouseOption.mouseY - dy) * (1 - (dheight - this.mouseOption.danH) / dheight)
                nwidth = dwidth - this.mouseOption.danW
                nheight = dheight - this.mouseOption.danH
            }
            // 向上滚动
            if (this.wheelDirection === 'up') {
                nx = dx - Math.abs(this.mouseOption.mouseX - dx) * ((dwidth + this.mouseOption.danW) / dwidth - 1)
                ny = dy - Math.abs(this.mouseOption.mouseY - dy) * ((dheight + this.mouseOption.danH) / dheight - 1)
                nwidth = dwidth + this.mouseOption.danW
                nheight = dheight + this.mouseOption.danH
            }
            // 移动
            if (this.wheelDirection === '') {
                nx = this.mouseOption.movementX + dx
                ny = this.mouseOption.movementY + dy
                nwidth = dwidth
                nheight = dheight
            }
            dom.dx = nx
            dom.dy = ny
            dom.dwidth = nwidth
            dom.dheight = nheight
            return {
                nx,
                ny,
                nwidth,
                nheight
            }
        },
        // 初始化canvas
        initCanvas() {
            this.canvasDom = document.querySelector('.my-canvas')
            this.canvasCtx = this.canvasDom.getContext('2d')
            this.imgDom = document.querySelector('.my-img')
            this.imgDom.onload = () => {
                console.log(this.imgDom.clientWidth, this.imgDom.clientHeight)
                this.imgRect.dwidth = this.imgRect.iwidth = this.imgDom.clientWidth
                this.imgRect.dheight = this.imgRect.iheight = this.imgDom.clientHeight
                this.mouseOption.danW = this.imgRect.iwidth * this.mouseOption.zoom
                this.mouseOption.danH = this.imgRect.iheight * this.mouseOption.zoom
                this.canvasCtx.drawImage(this.imgDom, 0, 0, this.imgDom.clientWidth, this.imgDom.clientHeight)
                this.canvasCtx.fillRect(5, 5, 30, 20)
                let imgData = this.canvasCtx.getImageData(20, 20, 50, 50)
                console.log(imgData, 'imgData')
                this.addListener()
            }
        }
    }
}
</script>

<style>
.my-img {
    /* display: none; */
}
.my-canvas {
}
.clip {
    position: absolute;
    border: 1px solid #fefefe;
    background: #eeeeee;
}
.dot {
    position: absolute;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    background: blue;
}
.dot:hover {
    cursor: pointer;
}
.lt {
    top: -5px;
    left: -5px;
}
.t {
    top: -5px;
}
.rt {
    top: -5px;
    right: -5px;
}
.l {
    left: -5px;
}
.r {
    right: -5px;
}
.lb {
    bottom: -5px;
    left: -5px;
}
.b {
    bottom: -5px;
}
.rb {
    bottom: -5px;
    right: -5px;
}
</style>
